package org.hagen.mmia.yars.agent;

import java.text.DecimalFormat;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Map.Entry;

import org.hagen.mmia.yars.agent.utils.FloatTreeMap;
import org.hagen.mmia.yars.client.User;
import org.hagen.mmia.yars.collection.Collection;
import org.hagen.mmia.yars.collection.Document;
import org.hagen.mmia.yars.agent.utils.IntegerTreeMap;

public class QueryPool {

	////////////////////////////////////////////////////////////////////////////////////////////////
	// Enable tracing for this module
	static final boolean	verbose = false;

	////////////////////////////////////////////////////////////////////////////////////////////////

	/*
	 *
	 */
	public IntegerTreeMap getDocumentFrequencies( Set<String> docIDs ) {

		IntegerTreeMap result = new IntegerTreeMap();
		
		for( String docID : docIDs ) {
		
			Document doc = Collection.getDocument( docID );
			
			SortedMap<String, Double> sortedTF = doc.getFrequencies();
			
			if( sortedTF == null ) {
				//System.err.println( "getDocumentFrequencies: doc.getSortedFrequencies returned null for docID " + doc.ID );
				continue;
			}
			
			Iterator<Entry<String, Double>> it=
					sortedTF.entrySet().iterator();
			
			while(it.hasNext()) {
				Entry<String, Double> e = it.next();
				
	            String   term  = (String)e.getKey();
	            
	            result.inc( term );
			}
		}

		return result;
	}
	
	////////////////////////////////////////////////////////////////////////////////////////////////

	/*
	 *
	 */
	public HashMap<String, Double> getOverallTerms( Set<String> docIDs ) {
		
		HashMap<String, Double> map = new HashMap<String, Double>();
		
		IntegerTreeMap df = getDocumentFrequencies( docIDs );
		
		for( String docID : docIDs ) {
			
			Document doc = Collection.getDocument( docID );
			
			SortedMap<String, Double> sorted = doc.getFrequencies(df);
			if( sorted == null ) {
				//System.err.println( "buildSkillsI: doc.getSortedFrequencies returned null for docID " + doc.ID );
				continue;
			}

			Iterator<Entry<String, Double>> it=
					sorted.entrySet().iterator();
			
			while(it.hasNext()) {
				Entry<String, Double> e = it.next();
				
	            String   term  = e.getKey();
	            Double	 value = e.getValue();
	            
	            Double v = null;
	            if( ( v = map.get(term) ) != null ) {
	            	value += v;
	            }

	            map.put( term, value );
			}
		}
		
		return map;
	}
	
	////////////////////////////////////////////////////////////////////////////////////////////////
	
	/*
	 * generate queries as tri-grams based on relevant-set
	 */
	public static Map<String,FloatTreeMap> generateQueries( Set<String> relSet ) {

		Iterator<Entry<String, Double>> it = null;
		Map<String,FloatTreeMap>   queries = new TreeMap<String, FloatTreeMap>();

		/*
		 * get term vector
		 */
		QueryPool ex = new QueryPool();
		Map<String, Double> mapTF = ex.getOverallTerms( relSet );
		ex = null;

		// sort this term vector
		SortedMap<String, Double> sortedMap = new TreeMap<String, Double>();

		MapComparator bvc = new MapComparator(mapTF);
		sortedMap = new TreeMap<String, Double>(bvc);
		sortedMap.putAll(mapTF);

		int qcnt = 0;

		while( qcnt < User.MAX_NO_OF_USERS ) {

			/*
			 * use only top-k entries
			 */
			SortedMap<String,Double> terms = new TreeMap<String,Double>();
			FloatTreeMap skills = new FloatTreeMap();
			
			int cnt = 0;
			it = sortedMap.entrySet().iterator();
			while(it.hasNext()) {
				Entry<String, Double> e = it.next();
				String t = e.getKey();
				Double v = e.getValue();
				
				if( verbose ) {
					DecimalFormat format = new DecimalFormat("##0.0000");
					System.out.print( "[" + cnt + "] " + t + " " + format.format( e.getValue() ) );
				}
				
				// add query term
				if( cnt >= 2*qcnt ) {
				
					if( cnt < User.MAX_QUERY_TERMS + 2*qcnt ) {
						terms.put( t, 1.0 );
					}
					if( cnt < User.MAX_TERMS_PER_USER_PROFILE + 2*qcnt ) {
						skills.add( t, v );
					}
				}
				
				if( verbose ) {
					System.out.print( "\n" );
				}
	
				cnt++;
			}

			String queryString = new String();
	
			for( String s : terms.keySet() ) {
				queryString += s + " ";
			}
			queries.put( queryString.trim() , skills );
	
			qcnt++;
		}
		
		return queries;
	}
	
}

class MapComparator implements Comparator<String> {

    Map<String, Double> base;
    public MapComparator(Map<String, Double> map) {
        this.base = map;
    }

    // Note: this comparator imposes orderings that are inconsistent with equals.    
    public int compare(String a, String b) {
        if (base.get(a) >= base.get(b) ) {
            return -1;
        } else {
            return 1;
        } // returning 0 would merge keys
    }
}
